/***************************************************************************************************
 *Copyright(C),2010-2017,Sumscope
 *FileName	:  pinyin_search_idfile.h
 *Author	:  scofined.qi
 *Version	:  1.0
 *Date		:  2017/06/04
 *Desc		:  //用于主要说明此程序文件完成的主要功能
 *Relation :
 *Others	:  //其他内容说明
 *Function :  //主要函数列表，每条记录应包含函数名及功能简要说明
 *History	:
 * //修改历史记录列表，每条修改记录应包含修改日期、修改者及修改内容简介
 ***************************************************************************************************/
#pragma once

#include "pinyin_search_define.h"
#include "pinyin_search_idvec.h"
#include "pinyin_search_key.h"
namespace qb {
namespace base {
namespace internal {
#define ROUND_ALIGN(NUM, SIZE) \
  ((NUM % SIZE == 0) ? NUM : ((NUM / SIZE + 1) * SIZE))
class IndexIdRange;
#ifdef WIN32
typedef unsigned __int64 u64;
#else
typedef unsigned long long u64;
#endif
class SingleMappingView;
class MultiMappingView;
class IndexIdFile {
  enum {
    SIGNATURE = 0xFEFEABCD,
    MEGA_BYTES = 1024 * 1024,
  };
  using MappingView = SingleMappingView;
  struct KeyHead {
    int m_offset;     // 在映射文件中的偏移量
    int m_signature;  // SIGNATURE
    int m_used;       // 已经使用的空间
    int m_bytes;      // 整块内存大小
    int m_capcity;    // 预留空间
    int m_length;     // 个数:24,8
                   // 高24位表示bid,低8位表示个数,对应InverseSet的key,value
    wchar_t m_key[4];  //
  };
  struct Block {  // 代表空余空间
    int bytes;
    bool valid;

   public:
    Block() : bytes(0), valid(false) {}
    Block(int b, bool v) : bytes(b), valid(v) {}
  };
  class KeyHeadMemory {
    typedef std::map<void*, KeyHead*> BackupMemory;
    typedef std::map<int, KeyHead*> OffsetMap;
    BackupMemory m_memory;  // 备份内存
    OffsetMap m_offsets;

   public:
    KeyHeadMemory() {}
    ~KeyHeadMemory();
    int GetSize() const { return m_memory.size(); }
    bool IsEmpty() const { return m_memory.empty(); }
    bool Free(void* memory, int offset, int bytes);
    KeyHead* GetHead(int offset, int bytes);
    KeyHead* AllocHead(int offset, int bytes);
    int GetMemoryBytes() const;
  };

  int m_align_size;  // 每个KeyHad对应数据占据内存的大小对齐值,大小必须是此数字的整数倍
  float m_reserve_ratio;  // 预留比例
  int m_increase_size;    // 文件每次变大递增的尺寸,默认32mb
  int m_sys_pagesize;  // 系统的页面大小,分配内存即按照此对齐

  int m_cur_filesize;  // 当前映射文件大小,通常是m_increase_size的整数倍
  int m_cur_usedsize;  // 已经使用的大小
#ifdef WIN32
  void* m_file;  // 文件句柄
#else
  int m_file;  // 文件句柄
#endif
  void* m_mapping;                // 映射文件句柄
  MappingView* m_view;            // 映射文件区域,随机映射区域
  std::map<int, Block> m_blocks;  //
  KeyHeadMemory m_keyheads;       // 备份内存,优先级高
  std::string m_fname;            // 文件名称
 public:
  IndexIdFile(int npageCount = 4);
  ~IndexIdFile();

 protected:
  bool Initialize(const char* fname);
  bool PrepareMapping(int maxSize);

 protected:
  void* AllocSpace(int bytes, int& offset);
  void FreeSpace(void* memory, int offset, int bytes);
  KeyHead* PrepareSpace(int offset, int bytes);
  void* AllocByMapping(int bytes);

 public:
  void Dump() const;
  int GetMemoryBytes() const;
  void Update(const InverseKey& key, IndexIdRange* iirange);
  bool AddKey(IndexIdRange* iirange, int key);
  bool RemoveKey(IndexIdRange* iirange, int key);
  bool GetIndexIdVec(const IndexIdRange* iirange, IndexIdVec& iivec);
};

}  // namespace internal
}  // namespace base
}  // namespace qb
